#!/usr/bin/env python

from liwe.module import LiweModule
import sys, os, mimetypes , stat , time, inspect

class DLManager ( LiweModule ):
	def __init__ ( self, liwe ):
		super ( DLManager, self ).__init__ ( liwe, "dl_manager" )

	TABLE = 'dl_manager'
	TABLE_FIELDS = [ 'id', 'id_obj', 'module', 'created', 'uid', 'name', 'descr', 'fsize', 'fext', 'hit' ]

	"""
	get function arguments	
	params:
		func:		function
		kwargs:
	"""
	def _get_func_args ( self, func = None, vals = {}, kwargs = {} ):
		
		args = {}
		keys = inspect.getargspec ( func ) [ 0 ]
		[ args [ k ] = vals [ k ] for k in keys if k != 'self' and k != 'kwargs' ]
		#sys.stderr.write ( "\n------------------ DL_MANAGER _get_func_args - args : %s \nkwargs : %s" % ( args, kwargs ) )
		[ kwargs.update ( { arg : args [ arg ] } ) for arg in args ]
		#sys.stderr.write ( "\n------------------ DL_MANAGER _get_func_args - kwargs" % kwargs )

	def _extra_modules ( self, module = '' ):
		"""	
		res = self.get_extra_modules ( module, limit = 0 ) [ 'results' ]
		if not res:
			return {}
		inj = {}
		mod = ''
		for met in res:
			if met [ 'module' ] != mod: mod = met [ 'module' ]
			inj [ mod ][ met.get ( 'method', '' ) ] = { 'invoke' : met.get ( 'invoke', '' ), 'id_obj' : met.get ( 'id_obj' , 0 ) }
		"""
		mod = self.cfg.get ( module )
		#sys.stderr.write ( "\n\n---------- _extra_modules: mod = %s, module = %s\n\n" % ( mod, module ) )
		#if any method specific param is assigned else it will use module generic ones
		if not mod: return {}
		for met, val in mod.iteritems ():
			if not val: val = {}
			mod [ met ][ 'rel_id' ] = val.get ( 'rel_id', mod [ 'default' ][ 'rel_id' ] )
	
		return mod

########################## ADMIN

	def add_file ( self, file_obj, name = "", descr = "", files_tags = "", id_file = 0, id_obj = 0, module = "", kwargs = None ):

		if not module: module = 'dl_manager'	

		unique_id = id_file
		update = 1
		if not id_file:
			unique_id = self._create_id ()
			update = 0

		#injection
		extra_mod = self._extra_modules ( module = module ) 
		if extra_mod and extra_mod.get ( 'add_file' ):
			extra_mod = extra_mod [ 'add_file' ]
			# add to kwargs defined params
			"""
			arg_lst = self._get_func_args ( self.add_file )
			[ kwargs.update ( { arg : locals () [ arg ] } ) for arg in arg_lst ]
			"""
			self._get_func_args ( self.add_file, locals (), kwargs )
			kwargs [ 'id_file' ] = unique_id 
			inj_res = self.liwe.invoke ( extra_mod [ 'invoke' ], ** kwargs )
			id_obj = inj_res.get ( 'id_obj' )
			#sys.stderr.write ( "\n------------------ DL_MANAGER ADD_FILE  inj: %s\nkwargs : %s" % ( inj, kwargs, ) )#\ninj_res = %s" % ( inj, kwargs, inj_res ) )

		if not update:
			fname = self._get_dir_name ( unique_id )

			if not name: name = file_obj [ 'filename' ]
			fil = file_obj [ 'file' ]
			fil.seek ( 0, os.SEEK_END )
			size = fil.tell ()
			fil.seek ( 0 )

			split = os.path.splitext ( file_obj [ 'filename' ] )
			if split:
				ext = split [ 1 ] [ 1 : ]
			else:
				ext = ""

			ext = ext.lower ()

			fout_name = os.path.join ( fname, "%s.%s" % ( unique_id, ext ) )
			fout = open ( fout_name, "wb" )
			fout.write ( fil.read () )
			fout.close ()

			#self._create_thumb ( fname, unique_id, fout_name, ext )

			dct = { "name" : name, "descr" : descr, "fsize" : size, "fext" : ext, "uid" : 0, "id_obj" : id_obj, "module" : module }
		else:
			dct = { "name" : name, "descr" : descr }
 
		self.dbm.update ( self.TABLE, dct, "id = %s" % unique_id, debug = self.debug () )

		# TAGS
		#sys.stderr.write ( "\n\n\n\n\n**----------------- DL_MANAGER add_file: files_tags = %s\n\n\n\n\n " % files_tags )
		self.liwe.invoke ( "tags.admin.del_all_tags", id_obj = unique_id, id_site = self.site_id, module = module )
                self.liwe.invoke ( "tags.ajax.tag_object", id_obj = unique_id, id_site = self.site_id, tags = files_tags, module = module )


	def edit_file ( self, id_file = 0, id_obj = 0, module = "", action = "", kwargs = {} ):

		if not module:
			module = 'dl_manager'	

		res = self.browse_files ( id_file = id_file , id_obj = id_obj, module = module, start_pos = 0, limit = 1, kwargs = kwargs ).get ( 'results' )
		if res:
			#tag objects
                	tags_str = ''
                	if id_file:

                        	tgs = self.liwe.invoke ( "tags.ajax.tags_list", id_obj = id_file, id_site = self.site_id, 
					 module = module, id_only = 0, names_only = 1 ).get ( 'tags' )

				dct = { "id_file" : id_file, 
					"id_obj" : res [ 0 ][ 'id_obj' ], 
					"name" : res [ 0 ][ 'name' ] , 
					"descr" : res [ 0 ][ 'descr' ], 
					"files_tags" : tgs }
				
				extra_mod = self._extra_modules ( module = module ) 
				if extra_mod and extra_mod.get ( 'edit_file' ):
					extra_mod = extra_mod [ 'edit_file' ]
					#sys.stderr.write ( "\n\n::::::::::: kwargs = %s\n\n" % kwargs )
                                        kwargs.update ( dct ) 
                                        rel_id = extra_mod [ 'rel_id' ] 
                                        kwargs [ rel_id ] = dct [ 'id_obj' ]

					inj_res = self.liwe.invoke ( extra_mod [ 'invoke' ], ** kwargs )
					if inj_res and inj_res.get ( 'row' ):
						#sys.stderr.write ( "---------------------- DL_MANAGER_CLASS EDIT FILE	inj_res: %s \n\n" % str ( inj_res ) )
						dct.update ( inj_res.get ( 'row' ) )
					#sys.stderr.write ( "---------------------- DL_MANAGER EDIT_CLASS 	EDIT FILE	dct: %s\n " % str ( dct ) )
				return dct
		return {}

	def _create_thumb ( self, path_name, unique_id, full_dest_name, ext ):
		style = ''
		if ext in EXT_IMGS:
			self._create_thumb_image ( path_name, unique_id, full_dest_name )

		elif ext in EXT_ARCH: style = 'arc'

		elif ext in EXT_EXE: style = 'exe'

		elif ext in EXT_DOC: style = 'doc'
		
		elif ext in EXT_PDF:
			fout_name = os.path.join ( path_name, "%s.%s%s" % ( unique_id , ext, "[0]" ) )
			icon_path = os.path.join ( path_name, "thumb_%s.jpg" % unique_id ) 
			os.system ( "convert -geometry %dx%d -colorspace RGB %s %s " % ( ICON_SIZE, ICON_SIZE, fout_name, icon_path ) )
		else:
                        self._create_thumb_image ( path_name, unique_id, icon_path )
		

	def _create_thumb_image ( self, path_name, unique_id, full_dest_name ):
		from os3.utils.image_handler import ImageHandler

		ih = ImageHandler ()
		im = ih.load ( full_dest_name )
		im.toRGB ()
		im.scale ( ICON_SIZE, ICON_SIZE )
		im.save ( os.path.join ( path_name, "thumb_%s.jpg" % unique_id ), "JPEG" )

	def _create_id ( self ):
		self.dbm.insert ( self.TABLE, { "created" : "*NOW()" } )
		return self.dbm.insert_id ()

	def _get_dir_name ( self, unique_id ):
		path = self.cfg [ 'base_path' ]
		path.append ( "%3.3d" % ( unique_id % 1000 ) )
		path.append ( "%2.2d" % ( unique_id % 100 ) )
		path = os.path.join ( * path )

		if not os.path.isdir ( path ): 
			try:
				os.makedirs ( path )
			except:
				self.liwe.set_error ( 999, 'Impossibile creare directory di destinazione' )
				return
		return path

	def _define_mime_type ( self, path_name = '' ):
		mimetypes.init ()
		mime = mimetypes.guess_type ( path_name )
		return mime

	def remove_attachments ( self, id_obj = 0, module = '' ):

		if not id_obj and not module:
			return
		ids = self.dbm.all_rows ( self.TABLE, [ 'id' ], conds = " id_obj = '%s' AND module = '%s' " % ( id_obj, module ) )
		#sys.stderr.write ( "\n\ndl_manager remove_attachments: ids = %s\n\n" % ids )
		if ids:
			for id_file in ids:
				self.remove_file ( id_file = id_file [ 'id' ], module = module, id_obj = id_obj )

	def remove_file ( self , path_name = '', id_file = 0, id_obj = 0, module = '', kwargs = {} ):
 
		#sys.stderr.write ( "DL_MANAGER_REMOVE_FILE path_name: %s, id: %s, id_obj: %s, module: %s, kwargs: %s \n" % ( path_name , id , id_obj , module , str ( kwargs ) ) )
		if not module:
			module = 'dl_manager'	

		#sys.stderr.write ( "DL_MANAGER_REMOVE_FILE module = %s " % module ) 
		extra_mod = self._extra_modules ( module = module ) 
		if extra_mod and extra_mod [ module ].get ( 'remove_file' ):
			extra_mod = extra_mod [ module ]
			"""
			arg_lst = self._get_func_args ( self.remove_file )
			[ kwargs.update ( { arg : locals () [ arg ] } ) for arg in arg_lst ]
			"""
			self._get_func_args ( self.remove_file, locals (), kwargs )
			rel_id = extra_mod [ 'rel_id' ]
			kwargs [ rel_id ] = id_obj
			inj_res = self.liwe.invoke ( extra_mod [ 'invoke' ], ** kwargs )
			#sys.stderr.write ( "DL_MANAGER_REMOVE_FILE kwargs = %s " % kwargs ) 

		# 0: no id, 1: errore del db, 2: errore file system
		if not id_file:
			self.liwe.set_error ( 0, 'Nessun id file' )
			return
		conds = []
		if id_file:
			conds.append ( "id = %s" % id_file )
		"""
		if id_obj:
			conds.append ( "id_obj = '%s'" % id_obj )
		"""
		db = self.dbm.delete ( self.TABLE, conds = " AND ".join ( conds ), debug = self.debug () )
		if not db:
			self.liwe.set_error ( 1, 'Errore durante la cancellazione del file dal database' )
			return 
		# TAGS elimina tags relativi al file
		self.liwe.invoke ( "tags.admin.del_all_tags", id_obj = id_file, id_site = self.site_id, module = module )

		try:
			os.remove ( path_name )
		except:
			self.liwe.set_error ( 2, 'Errore durante la cancellazione del file' )

########################## USER


	def browse_files ( self, id_file = 0, name = '' , descr = '', filters_tags = '', fext = '', page_view = '', id_obj = 0, date_start = None, date_end = None, module = '', order_by = '', start_pos = 0, limit = 10, kwargs = None ):
		conds = []
		clause = ''
		res = {}

		if not module: module = 'dl_manager'	
		#FIXME: modifica dependency injection
		extra_mod = self._extra_modules ( module = module ) 
		if extra_mod and extra_mod.get ( 'browse_files' ):
			extra_mod = extra_mod [ 'browse_files' ]
			inj_res = self.liwe.invoke ( extra_mod [ 'invoke' ], ** kwargs )
			extra_ids = inj_res.get ( 'ids' )
			#sys.stderr.write ( "------------------ DL_MANAGER BROWSE_FILE extra_ids : %s  - id obj: %s\n" % ( extra_ids, id_obj ) )
			#FIXME: vedere se eliminare questo if
			if not id_obj and not extra_ids: 
				return { "results" : [], "rows" : 0 }

			if id_obj:
				extra_ids.append ( id_obj )
			if extra_ids:
				id_obj = ','.join ( extra_ids )
			
		#sys.stderr.write ( "------------------ DL_MANAGER BROWSE_FILE id obj: %s - id_obj type = %s\n" % ( id_obj, type (id_obj) ) )
		if not order_by: order_by = 'name'
		if id_file: conds.append ( "id = %s " % id_file )
		if id_obj: conds.append ( "id_obj IN ( %s ) " % id_obj )

		if module and not id_file: conds.append ( "module = '%s' " % module )
		if name: conds.append ( "name LIKE '%%%s%%' " % name )
		if descr: conds.append ( "descr LIKE '%%%s%%' " % descr )
		if fext: conds.append ( "fext = '%s' " % fext )
		if filters_tags:
			tgs = self.liwe.invoke ( "tags.ajax.search", tag_names = filters_tags, id_site = self.site_id, module = module ) [ 'tags' ]

			ids = [ str ( t [ 'id_obj' ] ) for t in tgs ]

			if not ids: 
				return  { "results" : [] , "rows" : 0 }

			if ids:
				conds.append ( "id IN ( %s )" % ",".join ( ids ) )		

		if date_start and date_end and date_start != date_end:
			conds.append ( "date(created) BETWEEN '%s' AND '%s' " % ( date_start, date_end ) )

		clause = " AND ".join ( conds )
		extras = " ORDER BY %s " % order_by

		if limit : extras += " LIMIT %d,%d " % ( start_pos, limit )

		#self.dbm.debug = sys.stderr.write
		tot_rows = self.dbm.count ( self.TABLE, 'id' , clause )
		res = self.dbm.all_rows ( self.TABLE, self.TABLE_FIELDS, clause, extras = extras, debug = self.debug () )
		
		if res:
			for r in res:
				dir_str = self._get_dir_name (  r [ 'id' ] )
				file_path =  "%s/%s.%s" % ( dir_str, r [ 'id' ], r [ 'fext' ] )

				r [ 'dir' ]	= dir_str
				r [ 'path' ]	= file_path
				r [ 'mime' ]	= self._define_mime_type ( file_path )

				if page_view == 'details':
					details = self.file_details ( file_path , r [ 'module' ] )
					r.update ( details )

			"""			
			if page_view == 'details':
				for r in res:
					dir = self._get_dir_name (  r [ 'id' ] )
					details = self.file_details ( "%s/%s.%s" % ( dir, r [ 'id' ], r [ 'fext' ] ), r [ 'id' ], r [ 'module' ] )
					r.update ( details )
			"""
			return  { "results" : res, "rows" : tot_rows }
		
		res = {}

		return  { "results" : res, "rows" : tot_rows }


	def file_details ( self , path_name = '', id_file = 0, module = '' ):

		if not module:
                        module = 'dl_manager'
		fileStats = os.stat ( path_name )
		#tag objects
		tags_str = ''
		if id_file:
			tgs = self.liwe.invoke ( "tags.ajax.tags_list", id_obj = id_file, id_site = self.site_id, module = module, id_only = 0 ) [ 'tags' ]
			
                        tgs_names = [ str ( t [ 'name' ] ) for t in tgs ]
                        if tgs_names:
                                tags_str =  ", ".join ( tgs_names ) 		

		fileInfo = {

		   'Size' : fileStats [ stat.ST_SIZE ],

		   'LastModified' : time.ctime ( fileStats [ stat.ST_MTIME ] ),

		   'LastAccessed' : time.ctime ( fileStats [ stat.ST_ATIME ] ),

		   'CreationTime' : time.ctime ( fileStats [ stat.ST_CTIME ] ),

		   'Mode' : fileStats [ stat.ST_MODE ],
	
		   'Tags' : tags_str

		}

		return fileInfo

	"""
	set file header for download
	params:
		path_name:	full path to the file 
		file_name: 	if path_name is set: name of file
				otherwise id file in download_manager table ( path_name and file_name will be set )
	"""
	def download_file ( self, path_name = '', file_name = '' ):
		if not path_name:
			try: 
				id_file = int ( file_name )
			except:
				return

			res = self.dbm.single_row ( self.TABLE, self.TABLE_FIELDS, conds = "id = %s" % id_file )
			if not res:
				return

			file_dir = self._get_dir_name ( res [ 'id' ] )
			path_name = os.path.join ( file_dir, '%s.%s' % ( res [ 'id' ], res [ 'fext' ] ) )
			file_name = res [ 'name' ] 
			#sys.stderr.write ( path_name )

		data = open ( path_name, "rb" ).read ()
		mime = self._define_mime_type ( path_name )

		self.liwe.pyhp.set_header (  'Content-Type', "application/octet-stream" ) #mime [ 0 ] )
		# FIXME: i valori devono essere string
		self.liwe.pyhp.set_header (  'Content-Length', str ( len ( data ) ) )
		self.liwe.pyhp.set_header (  'Content-Transfer-Encoding', "binary" )
		self.liwe.pyhp.set_header (  'Content-Disposition', 'attachment; filename="%s"' % file_name )
		
		print data

	def _get_ext_list ( self ):
		res = self.dbm.all_rows ( self.TABLE, "fext", extras = "GROUP BY fext" )
		if res:
			return res
		return {}		

	def _get_mods_list ( self ):
		res = self.dbm.all_rows ( self.TABLE, "module", extras = "GROUP BY module" )
		if res:
			return res
		return {}		
